package exogwt.server.dao;

import exogwt.client.domain.JcrObject;
import exogwt.server.util.Exo;

import javax.jcr.Node;
import javax.jcr.RepositoryException;

import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.apache.commons.lang.StringUtils;

/**
 * @author Andriy Zhdanov
 */
public abstract class GenericDao<T extends JcrObject> {
    /**
     * Gets node if it exists.
     *
     * @param path absolute path to node
     * @return node if it exists
     * @throws RepositoryException if node does not exist
     * @throws RepositoryConfigurationException in case of configuration problems
     */
    protected Node getNode(String path) throws RepositoryException, RepositoryConfigurationException {
        Node rootNode = Exo.getSession().getRootNode();
        return rootNode.getNode(path);
    }

    /**
     * Creates node if it does not exist.
     *
     * @param rootNode base node (usually root node)
     * @param path relative path
     * @param nodetype type of node to create if node does not exists
     * @return node
     * @throws RepositoryException in case of unexpected error
     */
    protected Node getNode(Node rootNode, String path, String nodetype) throws RepositoryException {
        String[] tokens = StringUtils.split(path, '/');
        Node node = rootNode;
        for (String token : tokens) {
            if (!node.hasNode(token)) {
                node = node.addNode(token, nodetype);
            } else {
                node = node.getNode(token);
            }
        }
        return node;
    }

    /**
     * Gets string value of the property if it exists, or default value.
     * @param node node
     * @param property property
     * @param defaultValue default value
     * @return property value or defaultValue
     * @throws RepositoryException in case of unexpected error
     */
    protected String getStringProperty(Node node, String property, String defaultValue)
            throws RepositoryException {
        if (node.hasProperty(property)) {
            return node.getProperty(property).getString();
        } else {
            return defaultValue;
        }
    }

    public T getById(String path) {
        try {
            Node node = getNode(path);
            T instance = getInstance();
            loadObject(node, instance);
            return instance;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void save(T instance) {
        try {
            Node rootNode = Exo.getSession().getRootNode();
            Node node = getNode(rootNode, instance.getPath(), getNodeType());
            saveObject(node, instance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected abstract String getNodeType();

    protected abstract void loadObject(Node node, T object);

    protected abstract void saveObject(Node node, T object);

    protected abstract T getInstance();

}
